package fnic.prehand.action;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import fnic.jsontrans.DeviceId;
import fnic.prehand.common.AgentConfig;
import fnic.prehand.common.BlockQueueService;
import fnic.prehand.common.ProbeAuthService;
import fnic.prehand.esagent.activity_measure.ActiveLocalQueueRiver;
import fnic.prehand.esagent.activity_measure.PhoneAgent;

public class HttpGatherServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	private static final AgentConfig config = AgentConfig.getInstance();
	
	private static final ObjectMapper objectMapper = new ObjectMapper();  //确保线程安全
	private static final Logger LOG = Logger.getLogger(HttpGatherServlet.class);

	private final ProbeAuthService authInstance;
//	private final BlockQueueService queueInstance;
	private final PhoneAgent phoneAgent;
	/**
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	public HttpGatherServlet(String idx, String type, String ctlurl, String skurl, BlockQueueService queue){
//		queueInstance = queue;
		authInstance = new ProbeAuthService(skurl);
		phoneAgent = new PhoneAgent(idx, type, ctlurl, skurl);
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int pbtype;  //pbtype=1(默认),表示从PC探针收到的结果;  pbtype=2,表示从Phone探针收到的结果;  默认为1
		int probeid;
		String probetime;
		String httpbody;
		String saveQdata;
		String v = request.getParameter(DeviceId.COND_PROBE_VERSION);
		String ksession = request.getParameter(DeviceId.COND_PROBE_SESSION);
		String strPBType = request.getParameter(DeviceId.COND_PROBE_TYPE);

		LOG.info("request url：" + request.toString());
//		String uri= request.getRequestURI();
//		if(uri.equals("/index")){}
		double version = 0.9;
		if(v!=null){
			try{
				version= Double.parseDouble(v);
			}catch(NumberFormatException e){
				LOG.error(e.getMessage());
				//解析失败这里暂时通过
			}
		}
		
		if(strPBType == null){
			strPBType = "1";
		}
		
		try{
			probeid = Integer.parseInt(request.getParameter(DeviceId.COND_PROBE_ID));
			pbtype = Integer.parseInt(strPBType);
		}catch(NumberFormatException e){
			LOG.error(e.getMessage());
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}

		Map<String, String[]> parammaps = request.getParameterMap();
		
		if(!urlParamValidate(pbtype, version, ksession, parammaps)){
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}
		
//		if(!sessionKeyValidate(probeid, version, ksession)){
//			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
//			return;
//		}


		// probetime格式化
//		long time = System.currentTimeMillis();
//		Date date = new Date(time);
//		DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
//		probetime = dateFormat.format(date);

		httpbody = getHttpBody(request.getInputStream());
		

		if(!probeRecordsHandler(pbtype, probeid, version, httpbody, parammaps)){
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}

		response.setContentType("application/json;charset=utf-8");
		response.setStatus(HttpServletResponse.SC_OK);
	}
	
	private boolean urlParamValidate(int pbtype, double version, String sessionKey, Map<String, String[]> parammaps){		
		//probe发来的URL参数错误--URL参数不全返回失败
		if(pbtype == 1 && 
			parammaps.containsKey(DeviceId.COND_PROBE_ID)&&
			parammaps.containsKey(DeviceId.COND_TASK_ID)&&
			parammaps.containsKey(DeviceId.COND_EXEC_NUM)){
			if(version>1.0&&sessionKey==null){
				return false;
			}
			return true;
		}else if(pbtype == 2 && 
				parammaps.containsKey(DeviceId.COND_PROBE_TYPE)&&
				parammaps.containsKey(DeviceId.COND_PROBE_ID)){
			return true;
		}
		return false;
	}
	
	/**
	 * 进行安全校验,url中会添加 version=1.1&keySession=32位uuid
	 */
	private boolean sessionKeyValidate(int probeid, double version, String ksession){
		if (version > 1.0) {
			if (!authInstance.validSessionKey(probeid, ksession)&&config.getSessionKeyFlg() != 0) {
				return false;
			}
		}
		return true;
	}
	
	private String getHttpBody(InputStream stream){
		InputStreamReader isr = null;
		BufferedReader streamReader = null;
		StringBuilder probedata = null;
		String httpbody = null;
		boolean succeedfg = true;
		
		try {
			String tempString;
			isr = new InputStreamReader(stream, "UTF-8");
			streamReader = new BufferedReader(isr);
			probedata = new StringBuilder();
			while ((tempString = streamReader.readLine()) != null) {
				probedata.append(tempString);
			}
		} catch (Exception e) {
			LOG.warn("get httpbody exception - " + e.getMessage());
			succeedfg = false;
		} 
		if(succeedfg){
			httpbody = probedata.toString();
		}
		try {
			if (streamReader != null) {
				streamReader.close();
			}
			if (isr != null) {
				isr.close();
			}
		} catch (IOException e) {
			LOG.warn("close stream exception - " + e.getMessage());
		}
		LOG.info("http body:" + httpbody);
		return httpbody;
	}

	private boolean probeRecordsHandler(int pbtype, int probeid, double version, String httpbody, Map<String, String[]> parammaps){
		boolean handSucc = true;
		String jsonbody = httpbody.trim();
		if (jsonbody.charAt(0) == '[') {		
			ByteArrayOutputStream strOutStm = new ByteArrayOutputStream();
			try {
				//遍历json tree
				List<LinkedHashMap<String, Object>> list = objectMapper.readValue(jsonbody, List.class);
				for(Map<String, Object> map : list){
					objectMapper.writeValue(strOutStm, map);
					String singleResult = strOutStm.toString();
					strOutStm.reset();
					if(pbtype == 1){
						handSucc = constructJson(version, singleResult, parammaps);
					}else if(pbtype == 2){
						handSucc = constructPhoneJson(probeid, singleResult);
					}
				}
			} catch (JsonParseException e) {
				LOG.error("json array parse fail: "+e.getMessage());
				handSucc = false;
			} catch (JsonMappingException e) {
				LOG.error("json array parse fail: "+e.getMessage());
				handSucc = false;
			} catch (Exception e) {
				LOG.error("json array parse fail: "+e.getMessage());
				handSucc = false;
			} finally {
				if (strOutStm != null) {
					try {
						strOutStm.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						LOG.error("close stream fail: "+e.getMessage());
					}
				}
			}
		} else if (jsonbody.charAt(0) == '{') {
			if(pbtype == 1){
				handSucc =constructJson(version, jsonbody, parammaps);
			}else if(pbtype == 2){
				handSucc = constructPhoneJson(probeid, jsonbody);
			}
		} else {
			LOG.error("ESAgent.ProbeToAgent:  Illegal Json Format!");
		}
		
		return handSucc;
	}
	
	private String getHeadString(double version, Map<String, String[]> parammaps){
		Map<String, Object> head = new HashMap<String, Object>();
		String[] pid = parammaps.get(DeviceId.COND_PROBE_ID);
		String[] tid = parammaps.get(DeviceId.COND_TASK_ID);
		String[] num = parammaps.get(DeviceId.COND_EXEC_NUM);
		String[] sks = parammaps.get(DeviceId.COND_PROBE_SESSION);
		int p, t, n;
		try{
			p = Integer.parseInt(pid[0]);
			t = Integer.parseInt(tid[0]);
			n = Integer.parseInt(num[0]);
		}catch(Exception e){
			LOG.warn("parse probeid。。。 fail" + e.getMessage());
			return null;
		}
//		ProbeHead head = new ProbeHead(1, p, t, n);
		head.put(DeviceId.COND_PROBE_TYPE, 1);
		head.put(DeviceId.COND_PROBE_ID, p);
		head.put(DeviceId.COND_TASK_ID, t);
		head.put(DeviceId.COND_EXEC_NUM, n);
		if(version>1.0){
//			head.setSessionKey(sks[0]);
			head.put(DeviceId.COND_PROBE_SESSION, sks[0]);
		}
		ByteArrayOutputStream strOutStm = new ByteArrayOutputStream();
		try {
			objectMapper.writeValue(strOutStm, head);
		} catch (JsonParseException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return null;
		} catch (JsonMappingException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return null;
		} catch (Exception e) {
			LOG.error("head to String fail: "+e.getMessage());
			return null;
		}
		String headstr = strOutStm.toString();
		if (strOutStm != null) {
			try {
				strOutStm.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return headstr;
	}
	
	private boolean constructJson(double version, String singleResult, Map<String, String[]> parammaps){
		String headstring = getHeadString(version, parammaps);
		if (headstring == null) {
			return false;
		}
		String res = headstring + "|" + singleResult;
//		queueInstance.addInQueueItem(res);
		return true;
	}
	
	private boolean constructPhoneJson(int probeid, String singleResult){
		Map<String, Object> head = new HashMap<String, Object>();
		LinkedHashMap<String, Object> phoneRes;
		
		//获取taskid和sk
		try{
			phoneRes = (LinkedHashMap<String, Object>) objectMapper.readValue(singleResult, Map.class);
		} catch (JsonParseException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		} catch (JsonMappingException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		} catch (Exception e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		}
		
		head.put(DeviceId.COND_PROBE_ID, probeid);
		head.put(DeviceId.COND_PROBE_TYPE, 2);
		
		if(phoneRes.containsKey(DeviceId.COND_TASK_ID)){
			head.put(DeviceId.COND_TASK_ID, phoneRes.get(DeviceId.COND_TASK_ID));
		}
		if(phoneRes.containsKey(DeviceId.COND_EXEC_NUM)){
			head.put(DeviceId.COND_EXEC_NUM, phoneRes.get(DeviceId.COND_EXEC_NUM));
		}
		if(phoneRes.containsKey(DeviceId.COND_PROBE_SESSION)){
			head.put(DeviceId.COND_PROBE_SESSION, phoneRes.get(DeviceId.COND_PROBE_SESSION));
			phoneRes.remove(DeviceId.COND_PROBE_SESSION);
		}
		
		ByteArrayOutputStream headStm = new ByteArrayOutputStream();
		ByteArrayOutputStream bodyStm = new ByteArrayOutputStream();
		try {
			objectMapper.writeValue(headStm, head);
			objectMapper.writeValue(bodyStm, phoneRes);
		} catch (JsonParseException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		} catch (JsonMappingException e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		} catch (Exception e) {
			LOG.error("head to String fail: "+e.getMessage());
			return false;
		}
		
		String res = headStm.toString() + "|" + bodyStm.toString();
		phoneAgent.singleIndex(res);
//		queueInstance.addInQueueItem(res);
		try {
			headStm.close();
			bodyStm.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return true;
	}
}
